home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / psd.zip / INSTRUM.SCM < prev    next >
Text File  |  1992-07-10  |  18KB  |  619 lines

  1. ;;;;
  2. ;;;; instrum.scm 1.17
  3. ;;;;
  4. ;;;; psd -- a portable Scheme debugger, version 1.0
  5. ;;;; Copyright (C) 1992 Pertti Kellomaki, pk@cs.tut.fi
  6.  
  7. ;;;; This program is free software; you can redistribute it and/or modify
  8. ;;;; it under the terms of the GNU General Public License as published by
  9. ;;;; the Free Software Foundation; either version 1, or (at your option)
  10. ;;;; any later version.
  11.  
  12. ;;;; This program is distributed in the hope that it will be useful,
  13. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;;; GNU General Public License for more details.
  16.  
  17. ;;;; You should have received a copy of the GNU General Public License
  18. ;;;; along with this program; if not, write to the Free Software
  19. ;;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. ;;;; See file COPYING in the psd distribution.
  21.  
  22. ;;;;  Written by Pertti Kellomaki, pk@cs.tut.fi
  23.  
  24. ;;;; This file contains the actual instrumentation code.  For each
  25. ;;;; syntactic form X to be instrumented, there is a corresponding
  26. ;;;; procedure instrument-X. In addition, there are a few helpful
  27. ;;;; procedures for instrumenting expression sequences etc. The
  28. ;;;; procedures psd-car, psd-cdr etc. that are used here work just like
  29. ;;;; normal car, cdr etc., but they operate on pexps, which are sexps
  30. ;;;; with position information.  
  31.  
  32. ;;;
  33. ;;; Instrument source-file, writing the instrumented version to
  34. ;;; instrumented-file.
  35. ;;; 
  36.  
  37. (define instrument-file
  38.   
  39.   (let ((caadr caadr) (caddr caddr) (cadr cadr) (car car) (cdr cdr)
  40.               (close-output-port close-output-port) (cons cons)
  41.               (eof-object? eof-object?) (eq? eq?) (error error)
  42.               (list list) (map map) (newline newline) (not not)
  43.               (null? null?) (open-input-file open-input-file)
  44.               (open-output-file open-output-file) (pair? pair?)
  45.               (reverse reverse) (write write))
  46.     
  47.     
  48.     (lambda (source-file instrumented-file)
  49.       
  50. ;;;
  51. ;;; Instrument an expression.
  52. ;;;
  53.       
  54.       (define (instrument-expr expr)
  55.     
  56.     (define (wrap instrumented-expr)
  57.       
  58.       (define file-name car)    ; for accessing the position info
  59.       (define line-number cadr)
  60.       (define column caddr)
  61.       
  62.       `(psd-debug psd-val psd-set! psd-context
  63.               ',(pexp->sexp expr)
  64.               ,(file-name (psd-expr-start expr))
  65.               ,(line-number (psd-expr-start expr))
  66.               ,(line-number (psd-expr-end expr))
  67.               (lambda () ,instrumented-expr)))
  68.     
  69.     (cond
  70.      
  71.      ;; expressions of the form (symbol ...) that are
  72.      ;; potential special forms
  73.      ((and (psd-pair? expr)
  74.            (psd-symbol? (psd-car expr)))
  75.       (case (psd-expr-contents (psd-car expr))
  76.         ((and) (wrap (instrument-and expr)))
  77.         ((begin) (wrap (instrument-begin expr)))
  78.         ((case) (wrap (instrument-case expr)))
  79.         ((cond) (wrap (instrument-cond expr)))
  80.         ((define) (instrument-define expr))
  81.         ((do) (instrument-do expr))
  82.         ((if) (wrap (instrument-if expr)))
  83.         ((lambda) (wrap (instrument-lambda expr)))
  84.         ((let) (wrap (instrument-let expr)))
  85.         ((let*) (wrap (instrument-let* expr)))
  86.         ((letrec) (wrap (instrument-letrec expr)))
  87.         ((or) (wrap (instrument-or expr)))
  88.         ((quasiquote) (wrap (instrument-quasiquote expr)))
  89.         ((quote) (instrument-quote expr))
  90.         ((set!) (wrap (instrument-set! expr)))
  91.         
  92.         ;; anything we don't recognize must be a procedure call
  93.         (else
  94.          (wrap (instrument-call expr)))))
  95.      
  96.      ;; list that starts with a list must be a procedure call
  97.      ;; somewhere deep down 
  98.      ((psd-pair? expr)
  99.       (wrap (instrument-call expr)))
  100.      
  101.      ;; ordinary atoms
  102.      ((or (psd-symbol? expr)
  103.           (psd-number? expr)
  104.           (psd-string? expr)
  105.           (psd-vector? expr)
  106.           (psd-char? expr)
  107.           (psd-boolean? expr)
  108.           (psd-null? expr))
  109.       (wrap (pexp->sexp expr)))
  110.      
  111.      (else
  112.       (error "Can not handle " expr))))
  113.       
  114.       
  115. ;;;
  116. ;;; A wrapper that has visibility to all the given symbols is needed
  117. ;;; in a few places.
  118. ;;; 
  119.       
  120.       (define (access-wrapper exprs variables)
  121.     `(let ,(build-val-set-definitions variables)
  122.        ,@exprs))
  123.       
  124. ;;;
  125. ;;; Build definitions for psd-val and psd-set!
  126. ;;; Beware that variables can be a list of variables, a single
  127. ;;; variable or a list of the form (a b . c)
  128. ;;;
  129. ;;; The definitions are of the form
  130. ;;; 
  131. ;;;  ((psd-val (lambda (...) ...))
  132. ;;;   (psd-set! (lambda (...) ...)))
  133. ;;;   
  134. ;;; suitable for inclusion in a let form.
  135. ;;;
  136.       
  137.       (define (build-set-definition variables)
  138.     (let loop ((variables variables)
  139.            (set-body '()))
  140.       (cond ((null? variables)
  141.          `(lambda (psd-temp psd-temp2)
  142.             (case psd-temp
  143.               ,@set-body
  144.               (else (psd-set! psd-temp psd-temp2)))))
  145.         (else
  146.          (loop (cdr variables)
  147.                (cons `((,(car variables)) (set! ,(car variables) psd-temp2))
  148.                  set-body))))))
  149.       
  150.       (define (build-val-definition variables)
  151.     (let loop ((variables variables)
  152.            (val-body '()))
  153.       (cond ((null? variables)
  154.          `(lambda (psd-temp)
  155.             (case psd-temp
  156.               ,@val-body
  157.               (else (psd-val psd-temp)))))
  158.         (else
  159.          (loop (cdr variables)
  160.                (cons `((,(car variables)) ,(car variables))
  161.                  val-body))))))
  162.       
  163.       (define (build-val-set-definitions variables)
  164.     
  165.     ;; build a proper list out of the variable list, that can be a
  166.     ;; single symbol, list, or dotted list
  167.     (define (make-proper-list maybe-dotted-list)
  168.       (cond ((null? maybe-dotted-list) '())
  169.         ((pair? maybe-dotted-list)
  170.          (cons (car maybe-dotted-list)
  171.                (make-proper-list (cdr maybe-dotted-list))))
  172.         (else
  173.          (list maybe-dotted-list))))
  174.     
  175.     (let ((variables (make-proper-list variables)))
  176.       `((psd-val ,(build-val-definition variables))
  177.         (psd-set! ,(build-set-definition variables)))))
  178.       
  179.       
  180. ;;;
  181. ;;; A set! is instrumented by instrumenting the value.
  182. ;;; 
  183.       
  184.       (define (instrument-set! expr)
  185.     (let ((var (pexp->sexp (psd-cadr expr)))
  186.           (val (psd-caddr expr)))
  187.       `(set! ,var ,(instrument-expr val))))
  188.       
  189. ;;;
  190. ;;; Quote and quasiquote. We don't try to instrument anything
  191. ;;; that is inside a quasiquote.
  192. ;;;
  193.       
  194.       (define (instrument-quasiquote expr) 
  195.     `(quasiquote ,(pexp->sexp (psd-cadr expr))))
  196.       
  197.       (define (instrument-quote expr)
  198.     `(quote ,(pexp->sexp (psd-cadr expr))))
  199.       
  200. ;;;
  201. ;;; A body (expression sequece) is instrumented by instrumenting each
  202. ;;; of the expressions. If there are internal defines, they are turned
  203. ;;; into an equivalent letrec form and access procedures for them are
  204. ;;; also generated. 
  205. ;;;
  206.       
  207.       (define (instrument-body body)
  208.     
  209.     ;; Return the leading definitions as a list of pexps
  210.     (define (leading-definitions body)
  211.       (let loop ((body body)
  212.              (definitions '()))
  213.         (cond ((psd-null? body)
  214.            (reverse definitions))
  215.           ((and (psd-pair? (psd-car body))
  216.             (eq? 'define
  217.                  (pexp->sexp (psd-caar body))))
  218.            (loop (psd-cdr body)
  219.              (cons (psd-car body)
  220.                    definitions)))
  221.           (else
  222.            (reverse definitions)))))
  223.     
  224.     ;; Return the rest of the body as a pexp
  225.     (define (trailing-exprs body)
  226.       (let loop ((body body))
  227.         (cond ((psd-null? body) body)
  228.           ((and (psd-pair? (psd-car body))
  229.             (eq? 'define
  230.                  (pexp->sexp (psd-caar body))))
  231.            (loop (psd-cdr body)))
  232.           (else body))))
  233.     
  234.     ;; Given a define form, return a corresponding binding for a letrec
  235.     (define (build-letrec-binding definition variables)
  236.       `(,(definition-name definition)
  237.         ,(access-wrapper (list (build-definition-body definition)) variables)))
  238.     
  239.     
  240.     ;; If there are no internal definitions, do not wrap a redundant letrec
  241.     ;; around the body
  242.     (let ((definitions (leading-definitions body)))
  243.       (if (null? definitions)
  244.           
  245.           (psd-map instrument-expr body)
  246.           
  247.           ;; there were definitions, so we must wrap a letrec around the
  248.           ;; expressions that make up the body
  249.           (let ((variables (map definition-name definitions)))
  250.         `((letrec ,(map (lambda (binding)
  251.                   (build-letrec-binding binding variables))
  252.                 definitions)
  253.             ,(access-wrapper
  254.               (psd-map instrument-expr
  255.                    (trailing-exprs body))
  256.               variables)))))))
  257.       
  258.       
  259. ;;;
  260. ;;; Instrument (and ...)
  261. ;;;
  262.       
  263.       (define (instrument-and form)
  264.     (cons 'and (psd-map instrument-expr (psd-cdr form))))
  265.       
  266. ;;;
  267. ;;; Instrument (or ...)
  268. ;;;
  269.       
  270.       (define (instrument-or form)
  271.     (cons 'or (psd-map instrument-expr (psd-cdr form))))
  272.       
  273. ;;;
  274. ;;; Instrument (do ...)
  275. ;;; This is rather messy, because of the scoping rules of the do form.
  276. ;;; There is no convinient place to put the access procedures so that
  277. ;;; all variables would be visible at all times.
  278. ;;;
  279. ;;; The problem is that all the variables are visible at the update
  280. ;;; forms but not at the init forms. For this reason we have to wrap a
  281. ;;; let around every update form in order to get to the right values.
  282. ;;; The same applies to the test and result forms.
  283. ;;;
  284.       
  285.       (define (instrument-do form)
  286.     
  287.     ;; Instrument a do variable binding
  288.     (define (instrument-do-binding binding variables)
  289.       (let ((variable (pexp->sexp (psd-car binding)))
  290.         (init (psd-cadr binding))
  291.         (step
  292.          (if (psd-null? (psd-cddr binding))
  293.              (psd-car binding)
  294.              (psd-caddr binding))))
  295.         `(,variable ,(instrument-expr init)
  296.             ,(access-wrapper (list (instrument-expr step))
  297.                      variables))))
  298.     
  299.     
  300.     (let ((bindings (psd-cadr form))
  301.           (variables (let-variables (psd-cadr form)))
  302.           (test-result (psd-caddr form))
  303.           (body (psd-cdddr form)))
  304.       
  305.       `(do ,(psd-map (lambda (binding)
  306.                (instrument-do-binding binding variables))
  307.              bindings)
  308.            ,(psd-map instrument-expr
  309.              test-result)
  310.          ,@(instrument-body body))))
  311.       
  312.       
  313. ;;;
  314. ;;; Instrument (begin ...)
  315. ;;; 
  316.       
  317.       (define (instrument-begin form)
  318.     (cons 'begin (instrument-body (psd-cdr form))))
  319.       
  320. ;;;
  321. ;;; Instrument a let, let* or letrec binding list.
  322. ;;;
  323.       
  324.       (define (instrument-let-bindings bindings)
  325.     (let loop ((bindings bindings)
  326.            (result '()))
  327.       (if (psd-null? bindings)
  328.           (reverse result)
  329.           (let ((var (psd-expr-contents (psd-caar bindings)))
  330.             (expr (psd-cadar bindings)))
  331.         (loop (psd-cdr bindings)
  332.               (cons (list var
  333.                   (instrument-expr expr))
  334.                 result))))))
  335.       
  336. ;;;
  337. ;;; Return a list of variables being bound in a binding list.
  338. ;;;
  339.       
  340.       (define (let-variables bindings)
  341.     (psd-map (lambda (binding)
  342.            (psd-expr-contents (psd-car binding)))
  343.          bindings))
  344.       
  345. ;;;
  346. ;;; Instrument a let, let* or letrec form. We have to be aware of
  347. ;;; named let. 
  348. ;;;
  349.       
  350.       (define (instrument-let form)
  351.     (instrument-let-form form 'let))
  352.       
  353.       (define (instrument-let* form)
  354.     (instrument-let-form form 'let*))
  355.       
  356.       (define (instrument-letrec form)
  357.     (instrument-let-form form 'letrec))
  358.       
  359.       
  360.       (define (instrument-let-form form keyword)
  361.     (let ((bindings (if (psd-pair? (psd-cadr form))
  362.                 (psd-cadr form)
  363.                 (psd-caddr form)))
  364.           (name (if (psd-pair? (psd-cadr form))
  365.             '()
  366.             (list (pexp->sexp (psd-cadr form)))))
  367.           (body (if (psd-pair? (psd-cadr form))
  368.             (psd-cddr form)
  369.             (psd-cdddr form))))
  370.       `(,keyword ,@name ,(instrument-let-bindings bindings)
  371.              (let ,(build-val-set-definitions (let-variables bindings))
  372.                ,@(instrument-body body)))))
  373.       
  374.       
  375. ;;;
  376. ;;; Instrument a lambda.
  377. ;;;
  378.       
  379.       (define (instrument-lambda form)
  380.     (let ((variables (psd-cadr form))
  381.           (body (psd-cddr form)))
  382.       `(lambda ,(pexp->sexp variables)
  383.          (let ,(build-val-set-definitions (psd-map pexp->sexp variables))
  384.            ,@(instrument-body body)))))
  385.       
  386. ;;;
  387. ;;; Return the name of the variable being defined in a definition.
  388. ;;; 
  389.       (define (definition-name definition)
  390.     (let ((variable (psd-cadr definition)))
  391.       (pexp->sexp
  392.        (if (psd-pair? variable)
  393.            (psd-car variable)
  394.            variable))))
  395.       
  396. ;;;
  397. ;;; Build an instrumented body that corresponds to the definition. We
  398. ;;; need to be aware of (define foo ...) and (define (foo ...) ...).
  399. ;;;
  400. ;;; For each procedure definition of the form
  401. ;;; (define (foo x) ...) we supply a procedure definition that will
  402. ;;; give the name of this and surrounding procedures.
  403. ;;;
  404.       
  405.       (define (build-definition-body form)
  406.     (if (psd-pair? (psd-car (psd-cdr form)))
  407.         
  408.         ;; we have a (define (foo x) ...)
  409.         (let* ((heading (psd-car (psd-cdr form)))
  410.            (proc-name (psd-expr-contents (psd-car heading)))
  411.            (arguments (psd-map psd-expr-contents (psd-cdr heading)))
  412.            (body (psd-cdr (psd-cdr form))))
  413.           `(let ((psd-context
  414.               (lambda () (cons ',proc-name
  415.                        (psd-context)))))
  416.          (lambda ,arguments
  417.            (let ,(build-val-set-definitions arguments)
  418.              ,@(instrument-body body)))))
  419.         
  420.         ;; we have a (define foo ...)
  421.         (let ((expr (psd-caddr form)))
  422.           (instrument-expr expr))))
  423.       
  424. ;;;
  425. ;;; Instrument a define.
  426. ;;;
  427.       
  428.       (define (instrument-define form)
  429.     `(define ,(definition-name form) ,(build-definition-body form)))
  430.       
  431. ;;;
  432. ;;; Instrument an if.
  433. ;;;
  434.       
  435.       (define (instrument-if form)
  436.     (let ((condition (psd-car (psd-cdr form)))
  437.           (then-branch (psd-car (psd-cdr (psd-cdr form))))
  438.           (else-branch
  439.            (if (psd-null? (psd-cdr (psd-cdr (psd-cdr form))))
  440.            #f
  441.            (psd-car (psd-cdr (psd-cdr (psd-cdr form)))))))
  442.       (if else-branch
  443.           `(if ,(instrument-expr condition)
  444.            ,(instrument-expr then-branch)
  445.            ,(instrument-expr else-branch))
  446.           `(if ,(instrument-expr condition)
  447.            ,(instrument-expr then-branch)))))
  448.       
  449. ;;;
  450. ;;; Instrument a cond.
  451. ;;;
  452.       
  453.       (define (instrument-cond expr)
  454.     
  455.     (define (instrument-cond-clause clause)
  456.       (cond
  457.        
  458.        ;; else clause
  459.        ((and (psd-symbol? (psd-car clause))
  460.          (eq? (pexp->sexp (psd-car clause))
  461.               'else))
  462.         `(else ,@(instrument-body (psd-cdr clause))))
  463.        
  464.        ;; clause with just the predicate part
  465.        ((psd-null? (psd-cdr clause))
  466.         `(,instrument-expr (psd-car clause)))
  467.        
  468.        ;; ordinary clause
  469.        (else
  470.         `(,(instrument-expr (psd-car clause)) ,@(instrument-body (psd-cdr clause))))))
  471.     
  472.     `(cond ,@(psd-map instrument-cond-clause (psd-cdr expr))))
  473.       
  474. ;;;
  475. ;;; Instrument a case.
  476. ;;;
  477.       
  478.       (define (instrument-case expr)
  479.     
  480.     (define (instrument-case-clause clause)
  481.       (cond
  482.        
  483.        ;; else clause
  484.        ((and (psd-symbol? (psd-car clause))
  485.          (eq? (pexp->sexp (psd-car clause))
  486.               'else))
  487.         `(else ,@(instrument-body (psd-cdr clause))))
  488.        
  489.        ;; ordinary clause
  490.        (else
  491.         `(,(pexp->sexp (psd-car clause)) ,@(instrument-body (psd-cdr clause))))))
  492.     
  493.     `(case ,(instrument-expr (psd-cadr expr))
  494.        ,@(psd-map instrument-case-clause (psd-cddr expr))))
  495.       
  496. ;;;
  497. ;;; Instrument a procedure call. In case the call would cause a run
  498. ;;; time error, all the necessary information for invoking the
  499. ;;; debugger command loop is passed to psd-apply also. The value #f in
  500. ;;; the continuation position indicates to the command loop that the
  501. ;;; program can only be continued with a user supplied return value
  502. ;;; for the call.
  503. ;;;
  504.       
  505.       (define (instrument-call expr)
  506.     
  507.     (define file-name car)        ; for accessing the position info
  508.     (define line-number cadr)
  509.     
  510.     ;; (lambda x x) is used instead of list just in case someone
  511.     ;; wants to redefine list
  512.     `(psd-apply ((lambda x x) ,@(psd-map instrument-expr expr))
  513.             psd-val psd-set! psd-context
  514.             ',(pexp->sexp expr)
  515.             ,(file-name (psd-expr-start expr))
  516.             ,(line-number (psd-expr-start expr))
  517.             ,(line-number (psd-expr-end expr))
  518.             #f))
  519.       
  520.       
  521. ;;;
  522. ;;; Each instrumented file contains procedures that map the names of
  523. ;;; the top level symbols to the corresponding variables.
  524. ;;; 
  525.       
  526.       (define (build-global-accessors file-name)
  527.     
  528.     (define (build-accessor expr branches)
  529.       (if (or (not (pair? expr))
  530.           (not (eq? 'define (car expr))))
  531.           
  532.           ;; this was not a definition
  533.           branches
  534.           
  535.           ;; now we have to distinguis between (define foo ..) and
  536.           ;; (define (foo ...) ...)
  537.           (let ((var (if (pair? (cadr expr))
  538.                  (caadr expr)
  539.                  (cadr expr))))
  540.         (cons `((,var) ((lambda x x) ,var))
  541.               branches))))
  542.     
  543.     
  544.     (let ((port (open-input-file file-name)))
  545.       (let loop ((expr (pexp->sexp (psd-read port file-name)))
  546.              (case-branches '()))
  547.         (if (eof-object? expr)
  548.         
  549.         `(set! psd-global-symbol-accessors
  550.                (cons (lambda (psd-temp)
  551.                    (case psd-temp
  552.                  ,@case-branches
  553.                  (else #f)))
  554.                  psd-global-symbol-accessors))
  555.         
  556.         (loop (pexp->sexp (psd-read port file-name))
  557.               (build-accessor expr case-branches))))))
  558.       
  559.       
  560.       (define (build-global-setters file-name)
  561.     
  562.     (define (build-setter expr branches)
  563.       (if (or (not (pair? expr))
  564.           (not (eq? 'define (car expr))))
  565.           
  566.           ;; this was not a definition
  567.           branches
  568.           
  569.           ;; now we have to distinguis between (define foo ..) and
  570.           ;; (define (foo ...) ...)
  571.           (let ((var (if (pair? (cadr expr))
  572.                  (caadr expr)
  573.                  (cadr expr))))
  574.         (cons `((,var) (set! ,var psd-temp2))
  575.               branches))))
  576.     
  577.     
  578.     (let ((port (open-input-file file-name)))
  579.       (let loop ((expr (pexp->sexp (psd-read port file-name)))
  580.              (case-branches '()))
  581.         (if (eof-object? expr)
  582.         
  583.         `(set! psd-global-symbol-setters
  584.                (cons (lambda (psd-temp psd-temp2)
  585.                    (case psd-temp
  586.                  ,@case-branches
  587.                  (else #f)))
  588.                  psd-global-symbol-setters))
  589.         
  590.         (loop (pexp->sexp (psd-read port file-name))
  591.               (build-setter expr case-branches))))))
  592.       
  593.       
  594.       
  595.       
  596. ;;;
  597. ;;; Body of instrument-file
  598. ;;;
  599.       
  600.       (let* ((infile (open-input-file source-file))
  601.          (outfile (open-output-file instrumented-file)))
  602.     (set! *psd-source-line-number* 1)
  603.     (set! *psd-source-char-position* 1)
  604.     (let loop ((expr (psd-read infile source-file)))
  605.       (if (eof-object? expr)
  606.           (begin
  607.         (write (build-global-accessors source-file)
  608.                outfile)
  609.         (newline outfile)
  610.         (write (build-global-setters source-file)
  611.                outfile)
  612.         (newline outfile)
  613.         (close-output-port outfile))
  614.           (begin
  615.         (write (instrument-expr expr)
  616.                outfile)
  617.         (newline outfile)
  618.         (loop (psd-read infile source-file)))))))))
  619.